
#include <asset/assetsystem.h>
#include <asset/reader/assetreadereffect.h>
#include <asset/reader/assetreaderimage.h>
#include <asset/reader/assetreaderlevelofdetailsolver.h>
#include <asset/reader/assetreadermaterial.h>
#include <asset/reader/assetreadermesh.h>
#include <asset/reader/assetreaderprogram.h>
#include <asset/reader/assetreaderscenenode.h>
#include <asset/reader/assetreadershader.h>
#include <asset/reader/assetreadertexture.h>

ceAssetSystem::ceAssetSystem(ceEngine *engine)
	: _engine (engine)
{
	RegisterAssetReader(new ceAssetReaderEffect());
	RegisterAssetReader(new ceAssetReaderImage());
  RegisterAssetReader(new ceAssetReaderLevelOfDetailSolver());
	RegisterAssetReader(new ceAssetReaderMaterial());
	RegisterAssetReader(new ceAssetReaderMesh());
  RegisterAssetReader(new ceAssetReaderProgram ());
	RegisterAssetReader(new ceAssetReaderSceneNode());
	RegisterAssetReader(new ceAssetReaderShader());
	RegisterAssetReader(new ceAssetReaderTexture());
}


ceAsset *ceAssetSystem::AddAsset(ceAsset* asset)
{
	if (!asset)
		{
			return asset;
		}

  ceAsset* currentAsset = _assets[asset->GetAssetTypeID()][asset->GetLocator().GetName()];
	if (currentAsset == asset)
		{
			return asset;
		}
	if (currentAsset)
		{
			currentAsset->Release();
		}

  _assets[asset->GetAssetTypeID()][asset->GetLocator().GetName()] = asset;
	asset->AddRef();

	return asset;
}


ceAsset* ceAssetSystem::GetAsset(ceAssetTypeID typeID, const ceAssetLocator &locator)
{
	std::map<ceAssetTypeID, ceAssetMap>::iterator mit = _assets.find(typeID);
	if (mit == _assets.end())
		{
			ceAsset* asset = LoadAsset (typeID, locator);
			if  (asset)
				{
					// we don't inc the refound because we already have the reference
          _assets[typeID][locator.GetName()] = asset;
				}
			return asset;
		}

	ceAssetMap& map = mit->second;

	ceAssetMap::iterator ait = map.find(locator.GetName());
	if (ait == map.end())
		{
			ceAsset* asset = LoadAsset (typeID, locator);
			if  (asset)
				{
					// we don't inc the refound because we already have the reference
					_assets[typeID][locator.GetName()] = asset;
				}
			return asset;
		}

	return ait->second;
}

ceRef<ceAsset> ceAssetSystem::LoadAsset (ceAssetTypeID typeID, const ceAssetLocator& locator)
{
	for (unsigned i=0, j=_readers.size(); i<j; ++i)
		{
			iAssetReader* reader = _readers[i];
			if (reader && reader->CanRead(_engine, typeID, locator))
				{
					ceAsset* asset = reader->Read(_engine, typeID, locator);
					if (asset)
						{
							return asset;
						}
				}
		}
	return 0;
}


void ceAssetSystem::RegisterAssetReader(iAssetReader *reader)
{
	if (!reader)
		{
			return;
		}

	for (unsigned i=0, j=_readers.size(); i<j; ++i)
		{
			if (_readers[i] == reader)
				{
					return;
				}
		}

	_readers.push_back(reader);

	reader->AddRef();
}


void ceAssetSystem::UnregisterAssetReader(iAssetReader *reader)
{
	if (!reader)
		{
			return;
		}

	std::vector<iAssetReader*>::iterator it;
	for (it = _readers.begin(); it != _readers.end(); ++it)
		{
			iAssetReader* rdr = *it;
			if (rdr == reader)
				{
					rdr->Release();
					_readers.erase(it);
					return;
				}
		}
}
